<?php

namespace App\Master\Framework\Extend;

use GuzzleHttp\Client;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use PHPUnit\Exception;
use Ritaswc\ZxIPAddress\IPv4Tool;

class Core
{
    public static $_KEY = '5B9ADC14C705F1B041DDC2D9B16A2D94';

    public static $_IV = '33092152342590AD';

    public static function setCookie($key, $value, $time = 0, $path = '/', $domain = '', $httponly = false)
    {
        if (!$key || !$value)
        {
            return false;
        }
        $key = md5($key);
        $value = \GuzzleHttp\json_encode($value, JSON_UNESCAPED_UNICODE);
        $_COOKIE[$key] = $value;

        if ($value != null)
        {
            setcookie($key, $value, $time, $path, $domain, false, $httponly);
        } else {
            setcookie($key, '', $time, $path, $domain, false, $httponly);
        }

        return true;
    }

    public static function getCookie($key)
    {
        $key = md5($key);
        if (!isset($_COOKIE[$key])) {
            return false;
        }
        if(!$cookie_params = isset($_COOKIE[$key])?$_COOKIE[$key] :'')
        {
            return false;
        }

        try{
            return @json_decode($cookie_params, true);
        } catch (Exception $e)
        {
            return $cookie_params;
        }
    }

    public static function delCookie($key)
    {
        $key = md5($key);

        if (!isset($_COOKIE[$key])) {
            return true;
        }

        setcookie($key, '', -1, '/', '', false, false);

        return true;
    }

    public static function hosts()
    {
        $hosts = @$_SERVER['SERVER_NAME'];
        
        if ($_SERVER['SERVER_PORT'] == '443')
        {
            return 'https://'.$hosts;
            
        } else {
            if($_SERVER['SERVER_PORT'] == '80')
            {
                return 'http://'.$hosts;
            } else {
                return 'http://'.$hosts.':'.$_SERVER['SERVER_PORT'];
            }
        }
    }

    public static function HostDomain(){
        $domain = $_SERVER['HTTP_HOST'];
        $http = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
        return $http.$domain;
    }

    /**
     * 加密字符串
     * @param string | array $data 字符串
     * @param string $key 加密key
     * @param string $iv 加密向量  E8F2920CDT6GQ396
     * @return string
     */
    public static function encrypt($data, $key = '', $iv ='')
    {

        $key = $key ? $key : self::$_KEY;

        $iv = $iv ? $iv: self::$_IV;
        
        $encrypted = openssl_encrypt(
            \GuzzleHttp\json_encode($data, JSON_UNESCAPED_UNICODE),
            "AES-256-CBC",
            $key,
            OPENSSL_RAW_DATA,
            $iv);
        $encrypted = str_replace('=', '', base64_encode($encrypted));
        $encrypted = str_replace('+', '=A=', $encrypted);
        $encrypted = str_replace('&', '=B=', $encrypted);
        $encrypted = str_replace('/', '=C=', $encrypted);


        return  $encrypted;
    }


    /**
     * 解密字符串
     * @param string $data 字符串
     * @param string $key 加密key
     * @param string $iv 加密向量
     * @return array
     */
    public static  function decrypt($data, $key = '', $iv ='')
    {

        $key = $key ? $key : self::$_KEY;

        $iv = $iv ? $iv: self::$_IV;
        
        if(!$data || is_null($data))
        {
            return  [];
        }
        $data = str_replace('=A=', '+', $data);
        $data = str_replace('=B=', '&', $data);
        $data = str_replace('=C=', '/', $data);

        $decrypted = openssl_decrypt(
            base64_decode($data),
            'AES-256-CBC',
            $key,
            OPENSSL_RAW_DATA,
            $iv);
        if(!$decrypted) return false;
        $json_str = rtrim($decrypted, "\0");
        return \GuzzleHttp\json_decode($json_str, true);
    }
    
   
    public static function jsonResponse($status = 101, $msg = '', $data = [], $params = [])
    {
        $response = ['code' => intval($status), 'msg' => $msg, 'result' => $data, 'data' => $params];
        exit(json_encode($response, JSON_ERROR_RECURSION));
    }
    
    /**
     * 创建32位唯一表示.
     *
     * @param string $key 标识
     *
     * @return string
     */
    public static function createUnique($key = 'token')
    {
        return md5($key.uniqid(md5(microtime(true)), true).Str::random(12));
    }

    /**
     * stringToArray
     * 把字符串转换为数组
     *
     * @param string $string  需要处理的字符串
     * @access public
     * @since 1.0
     * @return array
     */
    public static function stringToArray($string){
        /*以逗号切割字符串;转换成数组*/

        if(!$items = explode(',', $string))
        {
            return [];
        }

        if(! $items = array_values(array_unique(array_filter($items))))
        {
            return [];
        }

        return $items;
    }

    /**
     * 递归
     * @param array $array 数据
     * @param string $index key
     * @param string $pid 父级key
     *
     * @return   array
     */
    public static function recursion($array, $index = 'id', $pid = 'parent_id')
    {
        //第一步 构造数据
        $items = [];
        if(empty($array))
        {
            return [];
        }
        foreach($array as $value)
        {
            $items[$value[$index]] = $value;
        }

        //第二部 遍历数据 生成树状结构
        $tree = array();
        foreach($items as $key => $item)
        {
            if(isset($items[$item[$pid]]))
            {
                $items[$item[$pid]]['children'][] = &$items[$key];
            }else{
                $tree[] = &$items[$key];
            }
        }
        return $tree;
    }

    public static function  DeepRecursion($array, $id = 0)
    {
        //初始化儿子
        $child = [];
        //循环所有数据找$id的儿子
        foreach ($array as $key => $datum)
        {
            //找到儿子了
            if ($datum['parent_id'] == $id)
            {
                //保存下来，然后继续找儿子的儿子
                $child[$datum['id']] = $datum;
                //先去掉自己，自己不可能是自己的儿孙
                unset($array[$key]);
                //递归找，并把找到的儿子放到一个child的字段中
                $child[$datum['id']]['children'] = self::DeepRecursion($array, $datum['id']);
            }
        }

        return $child;
    }

    public static function arrayColumnKey(array $items, $index = 'id'){
        if(empty($items))
            return [];
        $items_arr = [];
        foreach ($items as $val)
        {
            if(!isset($val[$index]))
                return [];
            $items_arr[$val[$index]] = $val;
        }
        unset($items);
        return $items_arr;
    }

    public static function formatDateSearch($date, $time = true)
    {
        if(empty($date))
        {
            return [0, 0];
        }

        list($start_date, $end_date) = explode(',', $date);
        if(!empty($start_date))
        {
            $start_date = $time ? strtotime($start_date. ' 00:00:00') : strtotime($start_date);
        }

        if(!empty($end_date))
        {
            $end_date = $time ? strtotime($end_date. ' 23:59:59') : strtotime($end_date);
        }

        return [$start_date, $end_date];
    }


    public static function explodeString($g = ',', $string ='')
    {
        return array_filter(array_unique(explode($g, $string)));
    }



    public static function getIpRegion($client_ip = ''){
        if(! $client_ip){
            if(isset($_SERVER['HTTP_X_REAL_IP']))
            {
                $client_ip = $_SERVER['HTTP_X_REAL_IP'];
            } else {
                $client_ip = Request::capture()->getClientIp();
            }
        }
        try {
            $result = IPv4Tool::query($client_ip);
            if(empty($result) || !isset($result['addr'])) {
                return '未知';
            }
            return isset($result['addr'][0]) ? $result['addr'][0] : '未知';
        }
        catch (\Exception $e) {
            return '未知';
        }
    }

    public static function authCode($string, $operation = 'DECODE', $key = '', $expiry = 0)
    {
        // 动态密匙长度，相同的明文会生成不同密文就是依靠动态密匙
        $ckey_length = 4;

        // 密匙
        $key = md5($key ? $key : '_KEY_');

        // 密匙a会参与加解密
        $keya = md5(substr($key, 0, 16));
        // 密匙b会用来做数据完整性验证
        $keyb = md5(substr($key, 16, 16));
        // 密匙c用于变化生成的密文
        $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
        // 参与运算的密匙
        $cryptkey = $keya.md5($keya.$keyc);
        $key_length = strlen($cryptkey);
        // 明文，前10位用来保存时间戳，解密时验证数据有效性，10到26位用来保存$keyb(密匙b)，
        //解密时会通过这个密匙验证数据完整性
        // 如果是解码的话，会从第$ckey_length位开始，因为密文前$ckey_length位保存 动态密匙，以保证解密正确
        $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) :  sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
        $string_length = strlen($string);
        $result = '';
        $box = range(0, 255);
        $rndkey = array();
        // 产生密匙簿
        for($i = 0; $i <= 255; $i++) {
            $rndkey[$i] = ord($cryptkey[$i % $key_length]);
        }
        // 用固定的算法，打乱密匙簿，增加随机性，好像很复杂，实际上对并不会增加密文的强度
        for($j = $i = 0; $i < 256; $i++) {
            $j = ($j + $box[$i] + $rndkey[$i]) % 256;
            $tmp = $box[$i];
            $box[$i] = $box[$j];
            $box[$j] = $tmp;
        }
        // 核心加解密部分
        for($a = $j = $i = 0; $i < $string_length; $i++) {
            $a = ($a + 1) % 256;
            $j = ($j + $box[$a]) % 256;
            $tmp = $box[$a];
            $box[$a] = $box[$j];
            $box[$j] = $tmp;
            // 从密匙簿得出密匙进行异或，再转成字符
            $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
        }
        if($operation == 'DECODE') {
            // 验证数据有效性，请看未加密明文的格式
            if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) &&  substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
                return substr($result, 26);
            } else {
                return '';
            }
        } else {
            // 把动态密匙保存在密文里，这也是为什么同样的明文，生产不同密文后能解密的原因
            // 因为加密后的密文可能是一些特殊字符，复制过程可能会丢失，所以用base64编码
            return $keyc.str_replace('=', '', base64_encode($result));
        }
    }

    /*获取手机号*/
    public static function GetPhoneLocation($phone){
        if(!$phone)  return false;
        $api_url = "http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel={$phone}&t=".time();
        $s = mb_convert_encoding((new Client())->get($api_url)->getBody()->getContents(),  "UTF-8", "GBK");
        preg_match_all("/(\w+):'([^']+)/", $s, $m);
        $data = [];
        if(isset($m[2])){
            foreach($m[1] as $key=>$val) {
                $data[$val] = $m[2][$key];
            }
            if(isset($data['carrier'])) {
                return $data['carrier'];
            }
        }
        $url = "https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query={$phone}&resource_id=6005&ie=utf8&oe=utf8&format=json";
        $response = @json_decode(file_get_contents($url), true);
        if($response && isset($response['data'])) {
            if(isset($response['data'][0])) {
                if($location = $response['data'][0]['prov'].$response['data'][0]['city'].' '.$response['data'][0]['type']){
                    return $location.'11';
                }
            }
        }
        return false;
    }

}
